<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// | 该文件的开源协议以所在项目的LICENSE文件为准，请遵守开源协议要求
// +----------------------------------------------------------------------
// | 账户余额
// +----------------------------------------------------------------------
namespace app\finance\http\api;

use app\admin\attributes\auth;
use app\finance\model\BalanceHistoryModel;
use app\finance\model\BalanceModel;
use app\finance\model\CashierModel;
use app\finance\model\RechargeModel;
use app\sso\model\UserModel;
use Inphp\Core\Db\Db;
use Inphp\Core\Db\PDO\Query;
use Inphp\Core\Modules;
use Inphp\Core\Object\Message;
use Inphp\Core\Util\Log;
use Inphp\Core\Util\Str;

#[auth] class balance
{
    /**
     * UID
     * @var int
     */
    public int $uid = 0;

    /**
     * 账户
     * @var array
     */
    public array $user = [];

    /**
     * 获取余额
     * @return array
     */
    public function index(): array
    {
        return BalanceModel::getBalance($this->uid);
    }

    /**
     * 获取列表
     * @param array|null $params
     * @return array
     */
    public function list(?array $params = null): array
    {
        $params = $params ?? getClient()->get;
        $admin = $params["admin"] ?? 0;
        $admin = $admin == 1 ? 1 : 0;
        $sso = Modules::getModule("sso");
        if (!$sso) {
            return [
                "rows"  => 0,
                "page"  => 1,
                "pages" => 0,
                "list"  => []
            ];
        }
        //判断是不是管理员
        $admin = $admin == 1 && ($this->user["admin"] == 1 || ($sso && !empty($this->user["groups"]) && \app\sso\model\UserModel::matchPermission(["finance/balance/balance"], $this->user["groups"])));
        $db = UserModel::emptyQuery("u")
            ->leftJoin(BalanceModel::as("b"), "u.uid=b.uid")
            ->select([
                "b.balance, b.integral",
                "u.uid, u.username, u.nickname, u.phone, u.countryCode"
            ]);
        if ($admin) {
            //可搜索
            $keyword = $params["keyword"];
            $keyword = !empty($keyword) ? Str::trim($keyword) : null;
            if (!empty($keyword)) {
                if ($sso) {
                    if (is_numeric($keyword) && strlen($keyword) < 12) {
                        //数字，查询手机号码
                        $db->whereLike("u.phone", $keyword);
                    } else {
                        //其它，查询昵称
                        $db->where(function(Query $q) use($keyword) {
                            $q->whereLike("u.username", $keyword)
                                ->orWhereLike("from_base64(substr(u.nickname, 23))", $keyword);
                        });
                    }
                }
            }
        } else {
            $db->where("u.uid", $this->uid);
        }
        //行数
        $rows = $db->rows();
        //当前页数
        $page = $params['page'] ?? 1;
        $page = is_numeric($page) && $page > 0 ? ceil($page) : 1;
        //总页数
        $pages = 1;
        //列表数据
        $list = [];
        if ($rows > 0) {
            $total = $params["total"] ?? 30;
            $total = is_numeric($total) && $total > 2 ? $total : 30;
            $pages = ceil($rows / $total);
            $page = $page > $pages ? $pages : $page;
            $offset = $total * ($page - 1);
            //可排序
            $config = Modules::getModule("finance")->getConfig("balance");
            if ($admin) {
                $obfList = array_keys($config["list"]);
                $obfList[] = "uid";
                $obf = $params["obf"] ?? "uid";
                $obf = in_array($obf, $obfList) ? $obf : "uid";
                $obt = $params["obt"] ?? "asc";
                $obt = $obt == "asc" ? "asc" : "desc";
                $db->orderBy("u.{$obf}", $obt);
            }
            $list = $db->get($total, $offset);
            foreach ($list as &$item) {
                if ($admin && $sso) {
                    $item['nickname'] = \app\sso\model\UserModel::decodeNickname($item['nickname']);
                }
                foreach ($config["decimal"] as $key=>$dec) {
                    $item[$key] = number_format($item[$key] ?? 0, $dec, '.', ',');
                }
            }
        }
        //返回列表数据，包含行数、页码、总页数、数据列表
        return compact("rows", "page", "pages", "list");
    }

    /**
     * 获取历史记录
     * @param array|null $params
     * @return array
     */
    public function history(?array $params = null): array
    {
        $params = $params ?? getClient()->get;
        $admin = $params["admin"] ?? 0;
        $admin = $admin == 1 ? 1 : 0;
        $sso = Modules::getModule("sso");
        if (!$sso) {
            return [
                "rows"  => 0,
                "page"  => 1,
                "pages" => 0,
                "list"  => []
            ];
        }
        //判断是不是管理员
        $admin = $admin == 1 && ($this->user["admin"] == 1 || ($sso && !empty($this->user["groups"]) && \app\sso\model\UserModel::matchPermission(["finance/balance/history"], $this->user["groups"])));
        $db = BalanceHistoryModel::emptyQuery("h")
            ->join(\app\sso\model\UserModel::tableName()." u", "h.uid=u.uid")
            ->select([
                "h.*",
                "u.username, u.nickname, u.phone, u.countryCode"
            ]);
        if ($admin) {
            //可搜索
            $keyword = $params["keyword"];
            $keyword = !empty($keyword) ? Str::trim($keyword) : null;
            if (!empty($keyword)) {
                if ($sso) {
                    if (is_numeric($keyword) && strlen($keyword) < 12) {
                        //数字，查询手机号码
                        $db->where(function (Query $q) use ($keyword) {
                            $q->whereLike("u.phone", $keyword)
                                ->orWhereLike("h.linkId", $keyword);
                        });
                    } else {
                        //其它，查询昵称
                        $db->where(function(Query $q) use($keyword) {
                            $q->whereLike("u.username", $keyword)
                                ->orWhereLike("h.log", $keyword)
                                ->orWhereLike("from_base64(substr(u.nickname, 23))", $keyword);
                        });
                    }
                }
            }
            //uid
            $uid = $params["uid"] ?? 0;
            $uid = is_numeric($uid) && $uid > 0 ? $uid : 0;
            if ($uid > 0) {
                $db->where("h.uid", $uid);
            }
        } else {
            $db->where("h.uid", $this->uid);
        }
        //行数
        $rows = $db->rows();
        //当前页数
        $page = GET('page', 1);
        $page = is_numeric($page) && $page > 0 ? ceil($page) : 1;
        //总页数
        $pages = 1;
        //列表数据
        $list = [];
        if ($rows > 0) {
            $total = GET("total", 30);
            $total = is_numeric($total) && $total > 2 ? $total : 30;
            $pages = ceil($rows / $total);
            $page = $page > $pages ? $pages : $page;
            $offset = $total * ($page - 1);
            //可排序
            $config = Modules::getModule("finance")->getConfig("balance");
            $list = $db->orderBy("h.id", "desc")->get($total, $offset);
            $balanceNames = BalanceModel::names();
            foreach ($list as &$item) {
                if ($admin && $sso) {
                    $item['nickname'] = \app\sso\model\UserModel::decodeNickname($item['nickname']);
                }
                $item["title"] = BalanceHistoryModel::translateCode($item["code"]);
                $item["amount"] = number_format($item["amount"], $config["decimal"][$item["name"]] ?? 2);
                $item["balance"] = number_format($item["balance"], $config["decimal"][$item["name"]] ?? 2);
                $item["balanceName"] = $balanceNames[$item["name"]] ?? "未知资产";
            }
        }
        //返回列表数据，包含行数、页码、总页数、数据列表
        return compact("rows", "page", "pages", "list");
    }

    /**
     * 管理员、财务操作余额
     * @return Message
     */
    public function update(): Message
    {
        $sso = Modules::getModule("sso");
        if (!$sso) {
            return httpMessage("缺少组件");
        }
        if ($this->user["admin"] != 1) {
            //判断是不是授权了
            if (!empty($this->user["groups"]) && $sso) {
                if (!\app\sso\model\UserModel::matchPermission("finance/balance/update", $this->user["groups"])) {
                    return httpMessage(31);
                }
            } else {
                return httpMessage(31);
            }
        }
        //用户UID
        $uid = POST("uid");
        $uid = is_numeric($uid) && $uid > 0 ? ceil($uid) : 0;
        if ($uid <= 0) {
            return httpMessage("UID参数无效");
        }
        //操作 扣还是充
        $method = POST("method");
        $method = in_array($method, ["plus", "minus", "increment", "decrement"]) ? $method : null;
        if (empty($method)) {
            return httpMessage("操作方式无效");
        }
        //资产
        $name = POST("name");
        $name = !empty($name) ? Str::trim($name) : null;
        if (empty($name)) {
            return httpMessage("资产类型无效");
        }
        $balanceList = Modules::getModule("finance")->getConfig("balance.list");
        if (!in_array($name, array_keys($balanceList))) {
            return httpMessage("资产类型无效");
        }
        //数额
        $amount = POST("amount");
        $amount = is_numeric($amount) && $amount > 0 ? $amount : 0;
        if ($amount <= 0) {
            return httpMessage("数额无效");
        }
        //日志说明
        $log = POST("log");
        $log = !empty($log) ? trim($log) : null;
        if (empty($log)) {
            return httpMessage("缺少原因说明");
        }
        $user = UserModel::getRowByPrimaryKey($uid);
        if (empty($user)) {
            return httpMessage("未找到账号");
        }
        if ($user["state"] != 1) {
            return httpMessage("账号状态不正常，禁止操作");
        }
        //非超管，都需要输入安全密码
        if ($this->user["admin"] != 1 && $sso) {
            $sp = POST("sp");
            $sp = !empty($sp) ? $sp : null;
            if (empty($sp) || strlen($sp) < 6 || strlen($sp) > 16) {
                return httpMessage("安全密码无效");
            }
            if (!UserModel::verifySPByUser($sp, $user)) {
                return httpMessage("安全密码错误");
            }
        }
        //保存
        if (!BalanceModel::{$method}($uid, $name, $amount, "admin", $log, 0, $this->uid)) {
            return httpMessage("操作失败，请稍后再试");
        }
        return httpMessage(0, "操作成功");
    }

    /**
     * 余额退款申请
     * @return Message
     */
    public function refundSubmit(): Message
    {
        //申请金额
        $amount = POST("amount");
        $amount = is_numeric($amount) && $amount > 0 ? round($amount, 2) : 0;
        if ($amount <= 0) {
            return httpMessage("请填写大于 0 的金额数字");
        }
        //申请原因和说明
        $reason = POST("reason");
        $reason = !empty($reason) ? trim($reason) : null;
        //查询余额
        $balance = BalanceModel::getBalance($this->uid);
        if ($balance["balanceTotal"] < $amount) {
            return httpMessage("余额不足，请填写正确金额");
        }
        //查询是否有正在申请的
        $rows = Db::from("finance_balanceRefund")
            ->where("uid", $this->uid)
            ->whereNotIn("state", [1,0])
            ->first();
        if (!empty($rows)) {
            return httpMessage("您有正在申请有退款");
        }

        $data = [
            "uid"       => $this->uid,
            "name"      => "balance",
            "amount"    => $amount,
            "reason"    => $reason,
            "state"     => 2
        ];

        $db = Db::from("finance_balanceRefund");
        if ($db->insert($data)) {
            $id = $db->getLastInsertId();
            //@BalanceModel::decrement($this->uid, "balance", $amount, "refund", "申请账户余额退款", $id);
            $res = $this->refundConfirm([
                "id"        => $id,
                "admin"     => true,
                "state"     => 1,
                "auto"      => 1
            ]);
            if ($res->error !== 0) {
                return httpMessage($res->message);
            }
            $refundAmount = number_format($res->data["refundAmount"] ?? 0, 2, ".", "");
            return httpMessage(0, "操作成功".($refundAmount > 0 ? "，已退款{$refundAmount}元" : ""), [
                "id"    => $id
            ]);
        }
        return httpMessage("操作失败，请稍后再试");
    }

    public function refundDetail(): Message
    {
        $id = GET("id");
        $id = is_numeric($id) && $id > 0 ? $id : 0;
        if ($id <= 0) {
            return httpMessage("ID 参数无效");
        }
        $db = Db::from("finance_balanceRefund")->where("id", $id);
        $sso = Modules::getModule("sso");
        $admin = $this->user["admin"] == 1 || ($sso && !empty($this->user["groups"]) && \app\sso\model\UserModel::matchPermission(["finance/balance/refund"], $this->user["groups"]));
        if (!$admin) {
            $db->where("uid", $this->uid);
        }
        $item = $db->first();
        if (empty($item)) {
            return httpMessage("未找到数据");
        }
        return httpMessage($item);
    }

    /**
     * 余额退款记录
     * @return array
     */
    public function refundList(): array
    {
        $db = Db::from("finance_balanceRefund r")->select(["r.*"]);

        $admin = GET("admin");
        //判断是不是管理员
        $sso = Modules::getModule("sso");
        $admin = $admin == 1 && ($this->user["admin"] == 1 || ($sso && !empty($this->user["groups"]) && \app\sso\model\UserModel::matchPermission(["finance/balance/refund"], $this->user["groups"])));

        if ($admin) {
            if ($sso) {
                $db->join(UserModel::as("u"), "r.uid=u.uid")
                    ->addSelect(["u.face, u.nickname, u.phone"]);
            }
            //超管
            $keyword = GET("keyword");
            $keyword = !empty($keyword) ? Str::trim($keyword) : null;
            if (!empty($keyword)) {
                if ($sso) {
                    if (is_numeric($keyword) && strlen($keyword) < 12) {
                        //数字，查询手机号码
                        $db->whereLike("u.phone", $keyword);
                    } else {
                        //其它，查询昵称
                        $db->where(function(Query $q) use($keyword) {
                            $q->whereLike("u.username", $keyword)
                                ->orWhereLike("from_base64(substr(u.nickname, 23))", $keyword);
                        });
                    }
                } else {

                }
            }
        } else {
            $db->where("r.uid", $this->uid);
        }
        //行数
        $rows = $db->rows();
        //当前页数
        $page = GET('page', 1);
        $page = is_numeric($page) && $page > 0 ? ceil($page) : 1;
        //总页数
        $pages = 1;
        //列表数据
        $list = [];
        if ($rows > 0) {
            $total = GET("total", 30);
            $total = is_numeric($total) && $total > 2 ? $total : 30;
            $pages = ceil($rows / $total);
            $page = $page > $pages ? $pages : $page;
            $offset = $total * ($page - 1);
            //可排序
            $list = $db->orderBy("r.id", "desc")->get($total, $offset);
            $balanceNames = BalanceModel::names();
            foreach ($list as &$item) {
                if ($admin && $sso) {
                    $item['nickname'] = \app\sso\model\UserModel::decodeNickname($item['nickname']);
                }
                $item["balanceName"] = $balanceNames[$item["name"]] ?? "未知资产";
            }
        }
        //返回列表数据，包含行数、页码、总页数、数据列表
        return compact("rows", "page", "pages", "list");
    }

    public function refundConfirm(?array $params = null): Message
    {
        $admin = false;
        if (!empty($params)) {
            $admin = $params["admin"] ?? false;
        }
        if (!$admin) {
            //判断是不是管理员
            $sso = Modules::getModule("sso");
            $admin = $this->user["admin"] == 1 || ($sso && !empty($this->user["groups"]) && \app\sso\model\UserModel::matchPermission(["finance/balance/refund"], $this->user["groups"]));
        }
        if (!$admin) {
            return httpMessage(31);
        }
        //
        $params = $params ?? getClient()->post;
        $id = $params["id"] ?? 0;
        $id = is_numeric($id) && $id > 0 ? $id : 0;
        if ($id <= 0) {
            return httpMessage("ID参数无效");
        }
        $state = $params["state"] ?? null;
        $state = $state == '0' || $state == '1' ? $state : null;
        if (is_null($state)) {
            return httpMessage("请指定处理结果");
        }
        //
        $auto = $params["auto"] ?? 0;
        $auto = $auto == 1;

        $data = Db::from("finance_balanceRefund")
            ->where("id", $id)
            ->first();
        if (empty($data)) {
            return httpMessage("未找到数据");
        }
        if ($data["state"] != 2) {
            return httpMessage("已处理的申请，不可重复处理");
        }
        $amount = bcsub($data["amount"], $data["refundAmount"], 2);
        if ($amount <= 0) {
            @Db::from("finance_balanceRefund")->where("id", $id)->update(["state"=>1]);
            return httpMessage(0, "已退款完成，无需重复操作");
        }
        $bak = $params["bak"] ?? '';
        $bak = !empty($bak) ? trim($bak) : null;

        if ($state == 0) {
            //关闭订单
            $db = Db::from("finance_balanceRefund")->where("id", $id)->set(["state" => 0, "bak" => $bak]);
            if (!$db->update()) {
                return httpMessage("操作失败，请稍后再试");
            }
            return httpMessage(0, "操作成功");
        }

        if ($auto) {
            //检测是否有足够的充值记录
            $rechargeList = RechargeModel::emptyQuery()
                ->where("uid", $data["uid"])
                ->where("payed", 1)
                ->whereRaw("`payedAmount`-`refundAmount`>0")
                //->orderBy("`payedAmount`-`refundAmount`", "desc")
                ->orderBy("payedTime", "desc")
                ->where("payedTime", ">", date("Y-m-d H:i:s", time()-90*86400))
                ->get();
            if (empty($rechargeList)) {
                return httpMessage("该用户90天内并没有充值记录，请使用手动退款处理");
            }
            $canRefundAmount = 0;
            foreach ($rechargeList as $item) {
                $canRefundAmount = bcadd($canRefundAmount, bcsub($item["payedAmount"], $item["refundAmount"], 2), 2);
            }
            if ($canRefundAmount < $amount) {
                return httpMessage("该用户的充值金额记录不足够本次退款");
            }
            //一笔笔退，退够为止
            $refundAmount = 0;
            $left = $amount;
            foreach ($rechargeList as $item) {
                $ca = bcsub($item["payedAmount"], $item["refundAmount"], 2);
                $ca = $ca > 0 ? $ca : 0;
                if ($ca <= 0) continue;
                $ra = min($left, $ca);
                $res = CashierModel::refundByCashierId($item["cashierId"], $ra, "余额申请退款", $this->uid, true);
                if ($res->error === 0) {
                    $left = bcsub($left, $ra, 2);
                    $refundAmount = bcadd($refundAmount, $ra, 2);
                    Log::writeToEnd(RUNTIME."/logs/finance/refund/".date("Ymd").".txt", "{$item['cashierId']}: 退款成功{$ra}");
                } else {
                    Log::writeToEnd(RUNTIME."/logs/finance/refund/".date("Ymd").".txt", "{$item['cashierId']}: ".($res->message ?? "退款失败"));
                }
                if ($left <= 0) {
                    continue;
                }
            }
        } else {
            $refundAmount = $params["refundAmount"] ?? 0;
            $refundAmount = is_numeric($refundAmount) ? $refundAmount : 0;
            $refundAmount = min($amount, $refundAmount);
        }
        $db = Db::from("finance_balanceRefund")->where("id", $id)->increment("refundAmount", $refundAmount)
            ->setRaw("state", "if(`refundAmount`>=`amount`, 1, 2)");
        if ($db->update()) {
            if ($refundAmount > 0 && !$auto) {
                @BalanceModel::decrement($data["uid"], "balance", $refundAmount, "refund", "申请账户余额退款", $id);
            }
            return httpMessage(0, "操作成功，已退款成功：{$refundAmount}", [
                "refundAmount"  => $refundAmount
            ]);
        }
        return httpMessage("操作失败，请稍后再试");
    }

    public function refundCancel(): Message
    {
        $id = POST("id");
        $id = is_numeric($id) && $id > 0 ? $id : 0;
        $db = Db::from("finance_balanceRefund")->where("id", $id);
        if ($this->user["admin"] != 1) {
            $db->where("uid", $this->uid);
        }
        if ($db->where("state", 2)->update(["state" => 0])) {
            return httpMessage(0, "已修改{$db->getAffectRows()}行数据");
        }
        return httpMessage("操作失败，请稍后再试");
    }
}